/**
 *
 * © Bahadir Zeren 2011
 * bzeren@gmail.com
 * No warranties, express or implied, are made for this program.
 *
 */
package org.baatar.opt.genetic.set.covering.binary;

import java.util.BitSet;
import org.baatar.opt.genetic.chromosome.IChromosome;
import org.baatar.opt.genetic.mutation.IMutator;
import org.baatar.util.RandomUtil;

/**
 * 
 * 
 * @author B_ZEREN
 */
public final class SCMutator implements IMutator<Boolean, BitSet> {

    private int chromosomeLength = 0;
    private double finalStableMutationRate = 50;
    private double iterationStepOfHOFSMR = 250.0;   //  iterationStepForHalfOfFinalStableMutationRate
    private double gradientOfMutationFunctionAtHOFSMR = 0.8;    //  gradientOfMutationFunctionAtHalfOfFinalStableMutationRate

//            po.setFinalStableMutationRate(pw.getChromosomeLength() / 90);
//            po.setIterationStepOfHOFSMR(250);
//            po.setGradientOfMutationFunctionAtHOFSMR(0.8);
//            po.setMutationProbablity(1.0);

    public SCMutator(int chromosomeLength,
                        double finalStableMutationRate,
                        double iterationStepOfHOFSMR,
                        double gradientOfMutationFunctionAtHOFSMR) {
        this.chromosomeLength = chromosomeLength;
        this.finalStableMutationRate = finalStableMutationRate;
        this.iterationStepOfHOFSMR = iterationStepOfHOFSMR;
        this.gradientOfMutationFunctionAtHOFSMR = gradientOfMutationFunctionAtHOFSMR;
    }

    @Override
    public IChromosome<Boolean, BitSet> mutate(IChromosome<Boolean, BitSet> chromosome,
                                                int iteration,
                                                float mutationRatio,
                                                RandomUtil random) throws CloneNotSupportedException {

        IChromosome<Boolean, BitSet> mutatedChromosome = null;

        int nogm = (int) Math.floor(finalStableMutationRate / (1 + Math.exp(-4.0 * gradientOfMutationFunctionAtHOFSMR * (iteration - iterationStepOfHOFSMR) / finalStableMutationRate)));
//double mutProb = (mutationProbablity * population[0].getNumOfCoveredColumns()) / (1.0 * chromosomeWrapper.getChromosomeLength());
//mutProb * (1.0 + (2 * numOfUselessIterations / maxNumOfUselessIterations)));

        for (int i = 0; i < chromosomeLength; i++) {

            if (random.getRandNumber(chromosomeLength) <= nogm) {

                boolean oBool = chromosome.getGeneValue(i);
                boolean nBool = oBool;

                if (oBool && random.getRandDouble() > mutationRatio) {
                    nBool = false;
                } else if ((!oBool) && random.getRandDouble() <= mutationRatio) {
                    nBool = true;
                }

                if (oBool != nBool) {

                    if (mutatedChromosome == null)
                        mutatedChromosome = (IChromosome<Boolean, BitSet>) chromosome.clone();

                    if (nBool) {
                        mutatedChromosome.setGeneValue(i, true);
                    } else {
                        mutatedChromosome.setGeneValue(i, false);
                    }

                }
            }
        }

        return mutatedChromosome;
    }

    /**
     * Clones the this object.
     * 
     * @return Object new cloned object.
     * 
     * @throws CloneNotSupportedException is trown if this object doesnt
     * implements Cloneable interface.
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
